package simulator.implementation.agent;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.JFrame;
import javax.vecmath.Vector3d;

import ai.ann.image.filter.filter.ImageFilter;
import ai.perception.Perceptor;
import ai.perception.RelativePosition;
import ai.perception.ShapeRelativePositionIdentifier;

import simbad.sim.CameraSensor;
import simbad.sim.RobotFactory;
import simulator.implementation.agent.essential.ControlledAgentWithInteralRepresentation;
import simulator.mv.ShapeBean;
import simulator.mv.VisionProcesser;

public class AgentRobot extends ControlledAgentWithInteralRepresentation{
	//Nested Classes:
	private class ImageViewer  extends JFrame{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		//Nested Class:3
		private class CameraImageCanvas extends Canvas{
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;
			//Attributes:
			private BufferedImage image;
			private LinkedList<ShapeRelativePositionIdentifier> shapes;
			//Constructor:
			public CameraImageCanvas(int w,int h){
				this.setSize(w,h);
				this.shapes = null;
			}
			//Methods:
			public void setImage(BufferedImage image){
				this.image = image;
				this.repaint();
			}
			public void setShapes(LinkedList<ShapeRelativePositionIdentifier> shapes){
				this.shapes = shapes;
				this.repaint();
			}
			private Color getOpositeTo(Color c){
				int r,g,b;
				r = 255-c.getRed();
				g = 255-c.getGreen();
				b = 255-c.getBlue();
				return new Color(r,g,b);
			}
			public void paint(Graphics g){
				g.drawImage(this.image,0,0,null);
				if(this.shapes!=null){
					Graphics2D g2D = (Graphics2D)g;
					for (Iterator<ShapeRelativePositionIdentifier> iter = this.shapes.iterator(); iter.hasNext();) {
						ShapeRelativePositionIdentifier identifier = iter.next();
						
						Rectangle tmp = identifier.getA().getRectangle();
						
						if(identifier.getProximityA()==RelativePosition.NEAR){
							g2D.setColor(Color.DARK_GRAY);
						}else if(identifier.getProximityA()==RelativePosition.MIDDLE){
							g2D.setColor(Color.LIGHT_GRAY);
						}else if(identifier.getProximityA()==RelativePosition.FAR){
							g2D.setColor(Color.WHITE);
						}else{
							g2D.setColor(this.getOpositeTo(identifier.getA().getColor()));
						}
						
						int horizontalLocation = identifier.getHorizontalLocation();
						String horizontal="";
						if(horizontalLocation == RelativePosition.LEFT){
							horizontal = "<";
						}else if(horizontalLocation == RelativePosition.RIGHT){
							horizontal = ">";
						}else if(horizontalLocation == RelativePosition.CENTER){
							horizontal = "-";
						}
						
						int verticalLocation = identifier.getVerticalLocation();
						String vertical="";
						if(verticalLocation == RelativePosition.UP){
							vertical = "^";
						}else if(verticalLocation == RelativePosition.DOWN){
							vertical = "V";
						}else if(verticalLocation == RelativePosition.CENTER){
							vertical = "-";
						}
						
						g2D.draw(tmp);
						g2D.setFont(new Font(Font.SERIF,Font.PLAIN,10));
						//g2D.drawString(description.getInformation(), (int)tmp.getCenterX(), (int)tmp.getCenterY());
						g2D.drawString(identifier.getA().getDescription().getInformation(), (int)tmp.getCenterX(), (int)tmp.getCenterY());
						g2D.drawString((horizontal+";"+vertical), (int)tmp.getCenterX(), (int)tmp.getCenterY()+10);
						
					}
				}
			}
		}
		//Constants:
		private final byte ADITIONAL = 30;
		//Attributes:
		CameraImageCanvas canvas;
		//Constructor:
		public ImageViewer(int w,int h){
			this.setSize(w+ADITIONAL,h+ADITIONAL);
			this.setVisible(true);
			this.canvas = new CameraImageCanvas(w,h);
			this.getContentPane().add(this.canvas);
		}
		//Methods:
		public void setImage(BufferedImage image){
			this.canvas.setImage(image);
		}
		public void setShapes(LinkedList<ShapeRelativePositionIdentifier> shapes){
			this.canvas.setShapes(shapes);
		}
	}
	//Attributes:
	private final Color GREEN = new Color(0,255,0);
	private final Color RED = new Color(255,0,0);
	private final int ERROR = 50;
	
	private CameraSensor camera;
	private BufferedImage cameraImage;
	private ImageViewer imageViewer;
	private ImageFilter filter;
	private Perceptor perceptor;
	//Constructor: 
	public AgentRobot(Vector3d position, String name) {
		super(position, name);
		this.step = 0;
		this.turn = 0;
		//Add a video camera:
		this.camera = RobotFactory.addCameraSensor(this);
		//Reserving memory to captured image:
		this.cameraImage = this.camera.createCompatibleImage();
		//Creating a little frame to see captured image:
		this.imageViewer = new ImageViewer(this.cameraImage.getWidth(),this.cameraImage.getHeight());
		//Creating Perseptor:
		this.perceptor = new Perceptor(this.cameraImage.getWidth(),this.cameraImage.getHeight());
		
		try {
			this.filter = new ImageFilter();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	//Methods:
	public void initBehavior() {}
	
	/*
	 * stepUp: Avanzar.
	 * stepDown: Retroceder.
	 * turnRight: Derecha.
	 * turnLeft: Izquierda.
	 * 
	 * getPerceptions(this) -> []
	 * 
	 * 
	 * */
	public void performBehavior() {
		//Capturar imagen desde la cámara:
		this.camera.copyVisionImage(this.cameraImage);
		
		if(this.filter!=null){
			//Show image captured by little frame:
			/**/
			//boolean[]selection={true,true,false,false,false,false};
			boolean[]selection={true,true,true,true,true,true};
			BufferedImage processedImage = this.filter.geFiltered(this.cameraImage, selection);
			
			LinkedList<ShapeBean> tmpShapes = new LinkedList<ShapeBean>();
			LinkedList<ShapeRelativePositionIdentifier> tmpIdentifiers = new LinkedList<ShapeRelativePositionIdentifier>();
			tmpShapes.addAll((VisionProcesser.getShapes(processedImage, this.GREEN, ERROR)));
			tmpShapes.addAll((VisionProcesser.getShapes(processedImage, this.RED, ERROR)));
			for (Iterator<ShapeBean> iter = tmpShapes.iterator(); iter.hasNext();) {
				ShapeBean element = iter.next();
				tmpIdentifiers.add(this.perceptor.getLocationBetween(element));
			}
			this.imageViewer.setShapes(tmpIdentifiers);
			/**/
			this.imageViewer.setImage(processedImage);
		}else{
			this.imageViewer.setImage(this.cameraImage);
		}
	}
}
